package main;

import jDialog.DeletePastGroup;
import jDialog.RandomGroups;
import jDialog.RemoveStudents;
import jDialog.ShowPastGroups;
import jOptionPane.ShowMessages;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Scanner;

import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.ScrollPaneConstants;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

public class RunGUI extends JFrame {
	private static final long serialVersionUID = 1L;

	private JTable table;
	private JScrollPane scrollTable;
	private String path, fileName;
	private ShowMessages sm;
	private boolean needToSave;
	private String currentlyOpenClass = "";
	private String[] tableColumns = { "<html><Center>First Name</Center></html>", "<html><Center>Last Name</Center><html>", "<html><Center>Include in Group</Center><html>" };

	public RunGUI() {
		path = "res/Files/";
		//path = "Files/";
		sm = new ShowMessages();
		needToSave = false;

		this.initFrame();
		this.initMenuBar();
		this.setVisible(true);
	}

	private void addClass() {
		String s = (String) JOptionPane.showInputDialog(this, "Enter name of Class:", "Input Box", JOptionPane.PLAIN_MESSAGE, null, null, "");
		if (s == null || s.equals(""))
			return;
		String fileName = s + ".txt";
		String fileDir = path + "Classes/";
		if (validClassName(fileName)) {
			File newfile = new File(fileDir, fileName);
			PrintWriter writer = null;
			try {
				writer = new PrintWriter(newfile);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			writer.close();
			this.open(fileName);
		} else {
			sm.ClassExist();
		}
	}

	private void addStudent(int numToAdd) {
		DefaultTableModel model = (DefaultTableModel) table.getModel();
		for (int i = 0; i < numToAdd; i++)
			model.addRow(new Object[] { "", "", false });
		this.revalidate();
	}

	private String[] ClassList() {
		File[] listOfFiles = new File(path + "Classes/").listFiles();
		String[] list = new String[listOfFiles.length];
		for (int i = 0; i < listOfFiles.length; i++)
			list[i] = listOfFiles[i].getName().substring(0, listOfFiles[i].getName().length() - 4);
		return list;
	}

	private int countLines(String filename) throws IOException {
		InputStream is = new BufferedInputStream(new FileInputStream(filename));
		try {
			byte[] c = new byte[1024];
			int count = 0;
			int readChars = 0;
			boolean empty = true;
			while ((readChars = is.read(c)) != -1) {
				empty = false;
				for (int i = 0; i < readChars; ++i) {
					if (c[i] == '\n') {
						++count;
					}
				}
			}
			return (count == 0 && !empty) ? 1 : count;
		} finally {
			is.close();
		}
	}

	private void initFrame() {
		this.setTitle("Create Random Groups");
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.addWindowListener(new WindowListener() {

			@Override
			public void windowActivated(WindowEvent arg0) {
			}

			@Override
			public void windowClosed(WindowEvent arg0) {
			}

			@Override
			public void windowClosing(WindowEvent arg0) {
				if (needToSave) {
					if (sm.needToSave(RunGUI.this) == JOptionPane.YES_OPTION) {
						RunGUI.this.save(true);
					}
				}
			}

			@Override
			public void windowDeactivated(WindowEvent arg0) {
			}

			@Override
			public void windowDeiconified(WindowEvent arg0) {
			}

			@Override
			public void windowIconified(WindowEvent arg0) {
			}

			@Override
			public void windowOpened(WindowEvent arg0) {
			}
		});
		this.setLayout(new BorderLayout());
		this.setSize(450, 300);
		this.setFrameLoc();
	}

	private void initMenuBar() {
		JMenuBar menu_bar = new JMenuBar();
		this.setJMenuBar(menu_bar);

		JMenu menuFile = new JMenu("File");
		menuFile.setMnemonic(KeyEvent.VK_F);
		JMenu menuEdit = new JMenu("Edit");
		menuEdit.setMnemonic(KeyEvent.VK_E);
		JMenu menuGroups = new JMenu("Groups");
		menuGroups.setMnemonic(KeyEvent.VK_G);

		menu_bar.add(menuFile);
		menu_bar.add(menuEdit);
		menu_bar.add(menuGroups);

		JMenuItem menuItem_FileOpen = new JMenuItem("Open");
		menuItem_FileOpen.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.CTRL_MASK));
		menuItem_FileOpen.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				if (needToSave) {
					if (sm.needToSave(RunGUI.this) == JOptionPane.YES_OPTION) {
						RunGUI.this.save(true);
					}
					needToSave = false;
				}
				RunGUI.this.open();
			}
		});
		JMenuItem menuItem_FileSave = new JMenuItem("Save");
		menuItem_FileSave.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_S, ActionEvent.CTRL_MASK));
		menuItem_FileSave.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				if (table != null) {
					RunGUI.this.save(true);
				}
			}
		});
		JMenuItem menuItem_FileExit = new JMenuItem("Exit");
		menuItem_FileExit.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				RunGUI.this.dispose();
			}
		});
		JMenuItem menuItem_EditAddClass = new JMenuItem("Add A Class");
		menuItem_EditAddClass.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				RunGUI.this.addClass();
			}
		});
		JMenuItem menuItem_EditRemoveClass = new JMenuItem("Remove A Class");
		menuItem_EditRemoveClass.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				RunGUI.this.removeClass();
			}
		});
		JMenuItem menuItem_EditAddStudent = new JMenuItem("Add A Student");
		menuItem_EditAddStudent.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				if (table != null) {
					RunGUI.this.addStudent(1);
				}
			}
		});
		JMenuItem menuItem_EditRemoveStudent = new JMenuItem("Remove A Student");
		menuItem_EditRemoveStudent.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				if (table != null) {
					RunGUI.this.removeStudent();
				}
			}
		});
		JMenuItem menuItem_EditAddStudents = new JMenuItem("Add Students");
		menuItem_EditAddStudents.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				if (table != null) {
					String strInput = (String) JOptionPane.showInputDialog(null, "How many students would you\n" + "like to add to the class?", "Input", JOptionPane.PLAIN_MESSAGE);
					int n;
					try {
						n = Integer.valueOf(strInput);
					} catch (NumberFormatException nfe) {
						return;
					}
					RunGUI.this.addStudent(n);
				}
			}
		});
		JMenuItem menuItem_EditRemoveStudents = new JMenuItem("Remove Students");
		menuItem_EditRemoveStudents.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				if (table != null) {
					RunGUI.this.removeStudents();
				}
			}
		});
		JMenuItem menuItem_PastGroupsShow = new JMenuItem("Show Past Group");
		menuItem_PastGroupsShow.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				new ShowPastGroups(RunGUI.this, path);
			}
		});
		JMenuItem menuItem_PastGroupsDelete = new JMenuItem("Delete A Past Group");
		menuItem_PastGroupsDelete.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				new DeletePastGroup(RunGUI.this, path);
			}
		});
		JMenuItem menuItem_MakeGroups = new JMenuItem("Make Groups");
		menuItem_MakeGroups.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent event) {
				if (table != null) {
					RunGUI.this.save(false);
					ArrayList<String> listTableInfo = new ArrayList<String>();
					for (int i = 0; i < table.getModel().getRowCount(); i++)
						if ((boolean) table.getModel().getValueAt(i, 2) == true) {
							String name = (String) table.getModel().getValueAt(i, 0) + " " + table.getModel().getValueAt(i, 1);
							listTableInfo.add(name);
						}
					if (listTableInfo.size() > 0)
						new RandomGroups(RunGUI.this, listTableInfo, path, fileName);
				}
			}
		});

		menuFile.add(menuItem_FileOpen);
		menuFile.add(menuItem_FileSave);
		menuFile.add(menuItem_FileExit);
		menuFile.addSeparator();
		menuFile.add(menuItem_EditAddClass);
		menuFile.add(menuItem_EditRemoveClass);

		menuEdit.add(menuItem_EditAddStudent);
		menuEdit.add(menuItem_EditRemoveStudent);
		menuEdit.add(menuItem_EditAddStudents);
		menuEdit.add(menuItem_EditRemoveStudents);

		menuGroups.add(menuItem_PastGroupsShow);
		menuGroups.add(menuItem_PastGroupsDelete);
		menuGroups.addSeparator();
		menuGroups.add(menuItem_MakeGroups);
	}

	private void initTable(String fileName) {
		int numOfLines = 1;
		String dir = path + "Classes/" + fileName;
		try {
			numOfLines = this.countLines(dir);
		} catch (IOException err) {
			return;
		}

		Object[][] tableData = new Object[numOfLines][tableColumns.length];
		Scanner fileScan = null, lineScan = null;
		try {
			fileScan = new Scanner(new File(dir));
		} catch (FileNotFoundException e) {
			return;
		}
		int count = 0;
		while (fileScan.hasNext()) {
			String line = fileScan.nextLine();
			lineScan = new Scanner(line);
			lineScan.useDelimiter(" ");
			tableData[count][0] = scan(lineScan.next());
			tableData[count][1] = scan(lineScan.next());
			tableData[count++][2] = true;
		}
		if (fileScan != null)
			fileScan.close();
		if (lineScan != null)
			lineScan.close();
		currentlyOpenClass = fileName;

		table = new JTable(new DefaultTableModel(tableData, tableColumns));
		table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		table.setAutoCreateRowSorter(true);
		table.getModel().addTableModelListener(new TableModelListener() {
			@Override
			public void tableChanged(TableModelEvent e) {
				needToSave = true;
			}
		});

		table.getColumnModel().getColumn(2).setCellEditor(table.getDefaultEditor(Boolean.class));
		table.getColumnModel().getColumn(2).setCellRenderer(table.getDefaultRenderer(Boolean.class));

		scrollTable = new JScrollPane(table);
		scrollTable.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
		table.setFillsViewportHeight(true);
		this.add(scrollTable);
		this.revalidate();
	}

	private void open() {
		fileName = (String) JOptionPane.showInputDialog(this, "What Class do you want to open?", "Input Box", JOptionPane.PLAIN_MESSAGE, null, this.ClassList(), "");
		this.setTitle("Create Random Groups - " + fileName);
		fileName += ".txt";
		try {
			this.remove(scrollTable);
		} catch (NullPointerException npe) {
		}
		this.initTable(fileName);
	}

	private void open(String fileName) {
		try {
			RunGUI.this.remove(scrollTable);
		} catch (NullPointerException npe) {
		}
		RunGUI.this.initTable(fileName);
	}

	private void removeClass() {
		String s = (String) JOptionPane.showInputDialog(this, "What Class do you want to delete?", "Input Box", JOptionPane.PLAIN_MESSAGE, null, this.ClassList(), "");
		try {
			File file = new File(path + "Classes/" + s + ".txt");
			sm.deleteFile(file.delete());
			if (currentlyOpenClass.equals(s + ".txt")) {
				RunGUI.this.remove(scrollTable);
				this.repaint();
			}
		} catch (Exception err) {
			err.printStackTrace();
		}
	}

	private void removeStudent() {
		if (table.getSelectedRow() != -1) {
			DefaultTableModel model = (DefaultTableModel) table.getModel();
			model.removeRow(table.getSelectedRow());
		}
	}

	private void removeStudents() {
		String[] classNames = new String[table.getRowCount()];
		for (int i = 0; i < table.getRowCount(); i++)
			classNames[i] = table.getModel().getValueAt(i, 0) + " " + table.getModel().getValueAt(i, 1);
		RemoveStudents mr = new RemoveStudents(this, classNames);
		mr.initTable();
		ArrayList<Integer> removeList = mr.initFrame();
		DefaultTableModel model = (DefaultTableModel) table.getModel();
		for (int i = removeList.size() - 1; i >= 0; i--)
			model.removeRow(removeList.get(i));
		this.revalidate();
	}

	private void save(boolean showMessage) {
		table.editCellAt(-1, -1);
		table.clearSelection();
		table.setEnabled(false);

		String dir = path + "Classes/" + currentlyOpenClass;
		File f = new File(dir);
		PrintWriter writer = null;
		try {
			writer = new PrintWriter(f);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		if (writer != null) {
			for (int row = 0; row < table.getRowCount(); row++) {
				String str = "";
				for (int col = 0; col < table.getColumnCount() - 1; col++) {
					String temp = String.valueOf(table.getModel().getValueAt(row, col));
					if (temp.equals(""))
						str += "_ ";
					else
						str += temp + " ";
				}
				writer.println(str);
			}

			writer.close();
			if (showMessage)
				sm.saveSuccess();
			needToSave = false;
		}
		table.setEnabled(true);
	}

	private String scan(String str) {
		return str.equals("_") ? "" : str;
	}

	private void setFrameLoc() {
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		int x = (int) ((d.getWidth() - this.getWidth()) / 2);
		int y = (int) ((d.getHeight() - this.getHeight()) / 2);
		this.setLocation(x, y);
	}

	private boolean validClassName(String name) {
		String fileDir = path + "Classes/";
		File folder = new File(fileDir);
		File[] listOfFiles = folder.listFiles();
		for (File f : listOfFiles)
			if (f.getName().equals(name))
				return false;
		return true;
	}
}